<?php

namespace app\api\controller\v12;

use app\api\controller\v2\Auth;
use app\common\cachemodel\Fortune;
use app\common\cachemodel\Orders as OrdersCacheModel;
use app\common\cachemodel\OrdersGoods;
use app\common\cachemodel\OrdersLib;
use app\common\cachemodel\RectificationEvent;
use app\common\cachemodel\UserCoupon;
use app\common\cachemodel\zlcr2\Zlcr2UserQuestion;
use app\common\lib\exception\ApiException;
use app\common\lib\PushQueue;
use app\common\model\MessageCenter;
use Exception;
use think\Db;
use think\Log;
use think\response\Json;

/**
 * 1.9.5订单控制器
 * Class Orders
 * @package app\api\controller\v12
 */
class Orders extends Auth
{
    public $msg;

    /**
     * 接口，订单列表
     * @return Json
     * @throws Exception
     */
    public function index()
    {
        $this->msg = '';
        OrdersLib::getUserAllUnpaidOrder($this->user['id']);
        $type = input('param.type/d', 0);
        $order_type = input('param.order_type/s', '');
        $version_code = input('param.version_code/d', 0);

        //1.9.6版本以后不需要过滤本命预测
        if ($version_code)
        {
            switch (true)
            {
                case $this->headers['app-type'] === 'ios' && $version_code >= 22:
                case $this->headers['app-type'] === 'android' && $version_code >= 34:
                    $orders = (new OrdersCacheModel())->getUserAllOrder($this->user['id'], $type, $order_type);
                    break;
                default:
                    $orders = (new OrdersCacheModel())->getUserAllOrder($this->user['id'], $type, $order_type, '7');
                    break;
            }
        } else
        {
            $orders = (new OrdersCacheModel())->getUserAllOrder($this->user['id'], $type, $order_type, '7');
        }
        if ($orders)
        {
            $array = [];
            foreach ($orders['data'] as $k => $order_detail)
            {
                $order = $this->index_data_format($order_detail);
                if ($order)
                {
                    $array[] = $order;
                }
            }
            $orders['data'] = $array;
        }
        return show(config('code.success'), '加载成功', $orders);
    }

    /**
     * 组合订单列表数据格式
     * @param $order_detail
     * @return array | string
     * @throws Exception
     */
    private function index_data_format($order_detail)
    {
        try
        {
            $order = OrdersLib::getOrderDetails($order_detail);
            if ($order === false)
            {
                return $this->msg = '订单数据错乱';
            }
            // 处理苹果审核时价格
            $order_detail['order_type'] = (int)$order_detail['order_type'];
            if ($this->is_apple_pay && $order_detail['order_type'] !== 8)
            {
                switch ($order_detail['order_type'])
                {
                    case 1:
                        $apple_goods = $this->apple_goods['rec_goods'];
                        break;
                    case 2:
                        $apple_goods = $this->apple_goods['fortune_day_goods'];
                        break;
                    case 3:
                        $apple_goods = $this->apple_goods['fortune_month_goods'];
                        break;
                    case 4:
                        $apple_goods = $this->apple_goods['fortune_year_goods'];
                        break;
                    case  5:
                        $apple_goods = $this->apple_goods['acg_goods'];
                        break;
                    case 6:
                        $apple_goods = $this->apple_goods['video_goods'];
                        break;
                    case 7:
                        $apple_goods = $this->apple_goods['natal_report_goods'];
                        break;
//                case 8:
//                    $apple_goods = $this->apple_goods['vip_goods'];
//                    break;
                    default:
                        $apple_goods = [];
                        break;
                }
                $total_amount = 0;
                foreach ($apple_goods as $ag)
                {
                    foreach ($order['goods_data'] as $gid => $odg)
                    {
                        if ((int)$ag['id'] === (int)$odg['id'])
                        {
                            $total_amount += $ag['now_prize'];
                            $order['goods_data'][$gid] = array_merge($odg, $ag);
                        }
                    }
                }
                $order_detail['total_amount'] = $total_amount;
            }
            $data = [];
            $data['data'] = [];
            $order_data = [];
            switch (true)
            {
                //重组校准生辰订单
                case (int)$order_detail['order_type'] === 1:
                    $data['order_name'] = '校准生辰';
                    $order_data['title'] = '校准生辰服务';
                    $order_data['des1'] = '出生时间：' . date('Y-m-d', $order['rectification_data']['start_time']);
                    $order_data['des2'] = '时间范围：' . date('H:i', $order['rectification_data']['start_time']) . '-' . ((date('d', $order['rectification_data']['start_time']) != date('d', $order['rectification_data']['end_time'])) ? '次日' : '') . date('H:i', $order['rectification_data']['end_time']);
                    $data['data'][] = $order_data;
                    break;
                //重组运势订单
                case in_array((int)$order_detail['order_type'], [2, 3, 4], true):
                    switch ($order_detail['order_type'])
                    {
                        case 2:
                            $order_data['title'] = '每日运势';
                            break;
                        case 3:
                            $order_data['title'] = '月度运势';
                            break;
                        case 4:
                            $order_data['title'] = '年度运势';
                            break;
                        default :
                            $order_data['title'] = '';
                            break;
                    }
                    $data['order_name'] = '运势订单';
                    $frame = [];
                    foreach ($order['recode_data'] as $for)
                    {
                        $frame[] = $for['name'];
                        $order_data['des2'] = '有效日期：' . $order['fortune_data']['start_time'] . '至' . $order['fortune_data']['end_time'];
                    }
                    $frame = $frame ? implode(',', $frame) : '';
                    $order_data['des1'] = '开通档案：' . $frame;
                    $data['data'][] = $order_data;
                    break;
                //重组地图订单
                case (int)$order_detail['order_type'] === 5:
                    $data['order_name'] = '幸运之城';
                    $order_data['title'] = '幸运之城解锁';
                    $map_recode = $order['recode_data'] ? current($order['recode_data']) : [];
                    $game = [];
                    foreach ($order['goods_data'] as $acg)
                    {
                        $game[] = $acg['name'];
                    }
                    $map_count = count($game);
                    $gabe_sta = $game ? implode(',', $game) : '';
                    if ($map_count > 2)
                    {
                        $des = '开通' . implode(',', array_slice($game, 0, 2)) . '等' . $map_count . '条';
                    } else
                    {
                        $des = '开通' . $gabe_sta . '等' . $map_count . '条';
                    }
                    $order_data['des1'] = '购买档案：' . $map_recode['name'];
                    $order_data['des2'] = '订单详情：' . $des;
                    $data['order_data'][] = [
                        'name' => '订单详情',
                        'value' => $gabe_sta
                    ];
                    $data['data'][] = $order_data;
                    break;
                //重组本命预测订单
                case (int)$order_detail['order_type'] === 7:
                    $data['order_name'] = '一生报告订单';
                    $order_data['title'] = '一生报告解锁';
                    $game = [];
                    foreach ($order['goods_data'] as $acg)
                    {
                        $game[] = $acg['name'];
                    }
                    $map_count = count($game);
                    $gabe_sta = $game ? implode(',', $game) : '';
                    if ($map_count > 1)
                    {
                        $des = '开通' . implode(',', array_slice($game, 0, 1)) . '等' . $map_count . '篇';
                    } else
                    {
                        $des = '开通' . $gabe_sta;
                    }
                    $order_data['des1'] = $des;
                    $data['order_data'][] = [
                        'name' => '订单详情',
                        'value' => $gabe_sta
                    ];
                    $data['data'][] = $order_data;
                    break;
                //重组视频订单
                case (int)$order_detail['order_type'] === 6:
                    $video_goods = $order['goods_data'] ? current($order['goods_data']) : [];
                    $data['order_name'] = '教学视频';
                    $data['video_id'] = $order['video_id'];
                    $order_data['title'] = $video_goods['name'];
                    $order_data['des1'] = $order['goods_data_des'];
                    $data['data'][] = $order_data;
                    break;
                //重组vip订单
                case (int)$order_detail['order_type'] === 8:
                    $vip_goods = $order['goods_data'] ? current($order['goods_data']) : [];
//                $vip_goods_des = json_decode($vip_goods['extend'], true)['goods_des'] ?? '';
                    $data['order_name'] = '开通会员';
                    $order_data['title'] = '会员开通';
                    $order_data['des1'] = '开通时长：' . $vip_goods['name'];
                    //若会员购买成功后，显示有效期
                    if ((int)$order['status'] === 4)
                    {
                        $order_data['des2'] = '有效期至：' . $order['vip_end_time'];
                    }
                    $data['data'][] = $order_data;
                    break;
            }
            $data['order_type'] = (int)$order_detail['order_type'];
            $data['order_status'] = $order['status_des'];
            $data['order_id'] = $order_detail['order_id'];
            $data['create_time'] = date('Y-m-d H:i:s', $order_detail['create_time']);
            $data['total_amount'] = $order_detail['total_amount'];
            $data['trade_type'] = (int)$order_detail['trade_type'];
            //获取订单按钮数据,列表没有取消订单
            if (isset($order['order_btn'][4]))
            {
                unset($order['order_btn'][4]);
            }
            $data['order_btns'] = $this->getIndexOrderBtn($order_detail);
            return $data;
        }
        catch (\Exception $e)
        {
            Log::write($this->user['id'] . '订单列表错误：' . $e->getMessage() . '【' . $e->getFile() . $e->getLine() . '】', 'error', true);
        }
        return [];
    }

    /**
     * 获取订单列表按钮
     * @param $orders
     * @return mixed
     */
    private function getIndexOrderBtn($orders)
    {
        $bans = config('zhunleorder');
        $data = $bans['index_order_btn'][$orders['status']];
        $array = [];
        if (in_array((int)$orders['status'], [3, 4], true) && in_array((int)$orders['order_type'], [1, 5, 6], true))
        {
            $array[] = array_shift($data);
        } else
        {
            $array = $data;
        }
        return $array;
    }

    /**
     * 接口，获取订单详情
     * @throws Exception
     */
    public function read()
    {
        $this->msg = '';
        $param = $this->request->only(['order_id', 'order_type']);
        if (!isset($param['order_id']) || !$param['order_id'])
        {
            return show(config('code.error'), '未知的订单');
        }
        $ordersCacheModel = new OrdersCacheModel();
        $orders = $ordersCacheModel->getInfoById($param['order_id']);
        if ($orders)
        {
            if ($orders['uid'] != $this->user['id'])
            {
                Log::write('非法订单查询：' . json_encode($param, true), 'error', true);
                return show(config('code.error'), '服务异常，请稍后重试～');
            }
            $info = $this->read_data_format($orders);
            return show(config('code.success'), '获取成功', $info);
        }
        return show(config('code.error'), '订单不存在');
    }

    /**
     * 组合订单详情数据格式
     * @param $orders
     * @return array
     * @throws Exception
     */
    private function read_data_format($orders)
    {
        try
        {
            $orders_details = OrdersLib::getOrderDetails($orders);
            // 处理苹果审核时价格
            if ($this->is_apple_pay && (int)$orders['order_type'] !== 8)
            {
                switch ((int)$orders['order_type'])
                {
                    case 1:
                        $apple_goods = $this->apple_goods['rec_goods'];
                        break;
                    case 2:
                        $apple_goods = $this->apple_goods['fortune_day_goods'];
                        break;
                    case 3:
                        $apple_goods = $this->apple_goods['fortune_month_goods'];
                        break;
                    case 4:
                        $apple_goods = $this->apple_goods['fortune_year_goods'];
                        break;
                    case  5:
                        $apple_goods = $this->apple_goods['acg_goods'];
                        break;
                    case 6:
                        $apple_goods = $this->apple_goods['video_goods'];
                        break;
                    case 7:
                        $apple_goods = $this->apple_goods['natal_report_goods'];
                        break;
//                case 8:
//                    $apple_goods = $this->apple_goods['vip_goods'];
//                    break;
                    default:
                        $apple_goods = [];
                        break;
                }
                $total_amount = 0;
                foreach ($apple_goods as $ag)
                {
                    foreach ($orders_details['goods_data'] as $gid => $odg)
                    {
                        if ((int)$ag['id'] === (int)$odg['id'])
                        {
                            $total_amount += $ag['now_prize'];
                            $orders_details['goods_data'][$gid] = array_merge($odg, $ag);
                        }
                    }
                }
                $orders_details['total_amount'] = $total_amount;
            }
            if ((int)$orders_details['status'] === 2)
            {
                //关闭超时订单
                $orders['status'] = 2;
            }
            //订单数据重组
            $data['order_id'] = $orders['order_id'];
            $info = [
                'status_des' => $orders_details['status_des'],
                'order_icon' => $this->getReadOrderBtn($orders)['icon'],
                'total_amount' => $orders_details['total_amount'],
                'order_id' => $orders['order_id'],
                'order_data' => $orders_details['order_data'],
                'is_skip' => $orders_details['is_skip'],
                'order_btn' => $this->getReadOrderBtn($orders)['btn'],
                'is_display_recommend_data' => $orders_details['is_display_recommend_data'],
            ];
            //订单描述，若为等待支付和进行中时有此字段
            if (isset($orders_details['des']))
            {
                $info['des'] = $orders_details['des'];
            }
            //剩余时间，以秒为单位（半小时为起始值） ， 若为等待支付时此字段有
            if (isset($orders_details['time_remaining']))
            {
                $info['time_remaining'] = $orders_details['time_remaining'];
            }
            //购买时的优惠券信息，无此字段不显示
            if (isset($orders_details['coupon_data']) && !$this->is_apple_pay)
            {
                $info['coupon_data'] = $orders_details['coupon_data'];
            }
            //购买时的折扣信息，无此字段不显示
            if (isset($orders_details['active_data']) && !$this->is_apple_pay)
            {
                $info['active_data'] = $orders_details['active_data'];
            }
            //重组购买的商品信息
            if (in_array((int)$orders['order_type'], [1, 2, 3, 4, 5, 6, 7, 8], true))
            {
                $goods = $orders_details['goods_data'] ? current($orders_details['goods_data']) : [];
                $info['goods_data']['price'] = $goods['now_prize'];
                $info['goods_data']['des'] = $orders_details['goods_data_des'] ?? '';

                switch (true)
                {
                    case (int)$orders['order_type'] === 1:
                        $info['goods_data']['name'] = '校准生辰服务';
                        break;
                    case (int)$orders['order_type'] === 2:
                        $info['goods_data']['name'] = '每日运势开通';
                        break;
                    case (int)$orders['order_type'] === 3:
                        $info['goods_data']['name'] = '月度运势开通';
                        break;
                    case (int)$orders['order_type'] === 4:
                        $info['goods_data']['name'] = '年度运势开通';
                        break;
                    case (int)$orders['order_type'] === 5:
                        $info['goods_data']['name'] = '幸运之城解锁';
                        // 处理幸运之城多订单购买时，价格错误问题
                        try
                        {
                            $info['goods_data']['price'] = array_sum(array_column($orders_details['goods_data'], 'now_prize'));
                        }
                        catch (Exception $e)
                        {
                            $info['goods_data']['price'] = 0;
                        }
                        break;
                    case (int)$orders['order_type'] === 7:
                        $info['goods_data']['name'] = '一生报告解锁';
                        try
                        {
                            $info['goods_data']['price'] = array_sum(array_column($orders_details['goods_data'], 'now_prize'));
                        }
                        catch (Exception $e)
                        {
                            $info['goods_data']['price'] = 0;
                        }
                        break;
                    case (int)$orders['order_type'] === 8:
                        $info['goods_data']['name'] = '开通会员';
                        $info['goods_data']['des'] = $goods['name'];
                        //若会员支付成功，则显示有效期
                        if ((int)$orders_details['status'] === 4)
                        {
                            $info['goods_data']['start_time'] = $orders_details['vip_start_time'] ?? '';
                            $info['goods_data']['end_time'] = $orders_details['vip_end_time'] ?? '';
                        }
                        break;
                    default:
                        $info['goods_data']['name'] = $goods['name'];
                        break;
                }

                //重组运势信息
                if (in_array((int)$orders['order_type'], [2, 3, 4], true))
                {
                    $info['goods_data']['start_time'] = $orders_details['fortune_data']['start_time'];
                    $info['goods_data']['end_time'] = $orders_details['fortune_data']['end_time'];
                }
                //重组视频信息
                if ((int)$orders['order_type'] === 6)
                {
                    $info['goods_data']['id'] = $orders_details['video_id'] ?? 0;
                }
            } else
            {
                $info['goods_data']['price'] = $orders_details['goods_data_price'];
                $info['goods_data']['des'] = $orders_details['goods_data_des'];
                $info['goods_data']['name'] = $orders_details['goods_name'] ?? $orders_details['goods_data_des'];
            }
            //重组购买的档案，无此字段不显示
            $recode_num = $orders_details['recode_data'] ? count($orders_details['recode_data']) : 0;
            $recode_rids = [];
            if ($recode_num)
            {
                if ($recode_num > 1)
                {
                    $info['recode_data']['des'] = $recode_num . '份档案';
                    foreach ($orders_details['recode_data'] as $recode_datum)
                    {
                        $recode_rids[] = $recode_datum['id'];
                    }
                } else
                {
                    $recode = current($orders_details['recode_data']);
                    $info['recode_data']['des'] = $recode['name'];
                    $recode_rids[] = $recode['id'];
                }
            }
            if ($recode_rids)
            {
                $info['recode_data']['rids'] = implode(',', $recode_rids);
            }

            //重组校准生辰事件信息，无此字段不显示
            if ((int)$orders['order_type'] === 1)
            {
                $info['goods_data']['id'] = $orders['reid'];
                $info['rectification_data']['des1'] = date('Y-m-d', $orders_details['rectification_data']['start_time']);
                $info['rectification_data']['des2'] = date('H:i', $orders_details['rectification_data']['start_time']) . '至' . ((date('d', $orders_details['rectification_data']['start_time']) != date('d', $orders_details['rectification_data']['end_time'])) ? '次日' : '') . date('H:i', $orders_details['rectification_data']['end_time']);
                //获取校准生辰事件信息
                $events = (new RectificationEvent())->batchGetInfoByIds($orders['reid'], ['id', 'status', 'reid', 'time', 'type', 'desc']);
                foreach ($events as $k => $event)
                {
                    unset($event['status'], $event['reid']);
                    $event['time'] = $event['time'] ? date('Y-m', $event['time']) : '';
                    $events[$k] = $event;
                }
                $info['rectification_data']['event'] = $events;
            }
            return $info;
        }
        catch (\Exception $e)
        {
            Log::write($orders['order_id'] . '订单详情错误：' . $e->getMessage() . '【' . $e->getFile() . $e->getLine() . '】', 'error', true);
        }
    }

    /**
     * 获取订单详情按钮和图标
     * @param $orders
     * @return mixed
     */
    private function getReadOrderBtn($orders)
    {
        $bans = config('zhunleorder');
        $data['icon'] = $bans['order_icon'][$orders['status']];
        $data['btn'] = $bans['read_order_btn'][$orders['status']];
        if (in_array((int)$orders['status'], [3, 4], true) && in_array((int)$orders['order_type'], [1, 5, 6], true))
        {
            $data['btn'] = [];
        }
        return $data;
    }

    /**
     * 检测单笔订单是否超时未支付
     * @param $orders
     * @return bool|Json
     */
    private function check_order_status($orders)
    {
        $ordersCacheModel = new OrdersCacheModel();
        $UserCouponModel = new UserCoupon();
        try
        {
            //更新缓存
            $ordersCacheModel->UpdateData($orders['order_id'], ['status' => 2], 2);
            //退回优惠券
            $extend = $orders['extend'] ? json_decode($orders['extend'], true) : [];
            $order_coupon = $extend['coupon'] ?? '';//获取订单的优惠券id
            if ($order_coupon)
            {
                $res2 = $UserCouponModel->use_return($this->user['id'], $order_coupon['cid'], ['status' => 0, 'oid' => 0, 'update_time' => $this->request->time()]);
                if ($res2 === false)
                {
                    return show(config('code.error'), $UserCouponModel->getError());
                }
            }
        }
        catch (Exception $e)
        {
            Log::write($orders['order_id'] . '订单超时关闭失败：' . $e->getMessage() . '【' . $e->getFile() . $e->getLine() . '】', 'error', true);
            return false;
        }
        return true;
    }

    /**
     * 接口，下单
     * order_type 1=>校准生辰,2=>日运,3=>月运,4=>年运,5=>幸运之城,6=>教学视频,7=>本命预测,8=>vip会员
     * order_id 01=>校准生辰 02=>运势 03=>幸运之城，04=>教学视频，05=>本命预测
     * @return Json
     * @throws Exception
     */
    public function pay_unlock()
    {
        $this->msg = '';
        $param['trade_type'] = input('param.trade_type/d', 0);
        $param['order_type'] = input('param.order_type/d', 0);
        $param['gids'] = input('param.gids/s', '');
        $param['param'] = input('param.param', '');
        $param['openid'] = input('param.openid/s', '');
        $param = OrdersLib::pay_order_param_format($this->user['id'], $param);
        if ($this->msg)
        {
            Log::write('v12下单请求参数有误：' . $this->msg, 'notice', true);
            return show(config('code.error'), $this->msg);
        }
        if ($param['price'] >= 0.01)
        {
            //生成订单数据并下单
            $arr = $this->SaveOrder($param);
            return show(config('code.success'), '下单成功', $arr['data']);
        }
        return show(config('code.error'), '下单金额错误');
    }

    /**
     * 接口，免费下单
     * @throws ApiException
     * @throws Exception
     */
    public function free_pay_unlock()
    {
        $this->msg = '';
        $param['trade_type'] = input('param.trade_type/d', 0);
        $param['order_type'] = input('param.order_type/d', 0);
        $param['gids'] = input('param.gids/s', '');
        $param['param'] = input('param.param', '');
        $param['openid'] = input('param.openid/s', '');
        $param = OrdersLib::pay_order_param_format($this->user['id'], $param);
        if ($this->msg)
        {
            Log::write('v12免费下单请求参数有误：' . $this->msg, 'notice', true);
            return show(config('code.error'), $this->msg);
        }
        if ($param['price'] <= 0)
        {
            //使用免费券或支付金额小于0
            $data = $this->SaveFreeOrder($param);
            return show(config('code.success'), '下单成功', ['order_id' => $data]);
        }
        return show(config('code.error'), '下单金额有误');
    }

    /**
     *  接口，关闭订单
     * @return Json
     * @throws Exception
     */
    public function close_order()
    {
        $param = $this->request->only(['order_id']);
        if (!isset($param['order_id']) || !$param['order_id'])
        {
            return show(config('code.error'), '未知的订单');
        }
        $OrdersModel = new OrdersCacheModel();
        $orders = $OrdersModel->getInfoById($param['order_id']);
        //订单存在切为未支付状态
        if ($orders && $orders['uid'] == $this->user['id'])
        {
            if ((int)$orders['order_type'] === 22 && in_array($orders['status'], [0, 1], false))
            {
                //问题被接单后不可取消
                $question = (new Zlcr2UserQuestion())->getInfoById($orders['fid'], ['status']);
                if (!in_array($question['status'], [1, 2], true))
                {
                    return show(config('code.error'), '当前订单不可取消');
                }
                OrdersLib::CloseOrder($orders);
                $messageData = [
                    'status' => 0,
                    'is_read' => 0,
                    'range' => $this->user['id'],
                    'type' => 2,
                    'article_comment_id' => 0,
                    'article_comment_reply_id' => 0,
                    'reid' => 0,
                    'cid' => 0,
                    'title' => '订单取消成功',
                    'content' => "订单取消成功，你开启的悬赏问答，订单编号：{$param['order_id']}已取消成功，资金将原路返还，请注意查收 ",
                    'link' => '',
                    'target' => '',
                    'create_time' => time()
                ];
                //添加消息中心
                (new MessageCenter())->pushMessage($this->user['id'], $messageData);
                return show(config('code.success'), '操作成功');
            }
            if ((int)$orders['status'] === 0)
            {
                OrdersLib::CloseOrder($orders);
                return show(config('code.success'), '操作成功');
            }
            return show(config('code.error'), '当前订单不可关闭');
        }
        return show(config('code.error'), '订单不存在');
    }

    /**
     * 运势下单
     * @param int $rid
     * @param int $start_time
     * @param int $order_type
     * @return bool|int|string
     */
    private function pay_fortune($rid, $start_time, $order_type)
    {
        $arr = [
            'type' => $order_type - 1,
            'rids' => $rid,
            'time' => $start_time,
            'create_time' => $this->request->time(),
        ];
        try
        {
            $fid = (new Fortune())->insertGetId($arr); //每日运势id
        }
        catch (Exception $e)
        {
            return false;
        }

        return $fid;
    }

    /**
     * 地图下单
     * @param $rid
     * @param $gids
     * @param $oid
     * @return bool
     */
    private function pay_map($rid, $gids, $oid)
    {
        $array = [];
        foreach ($gids as $k => $v)
        {
            $array[] = [
                'gid' => $v,
                'oid' => $oid,
                'rid' => $rid
            ];
        }
        //中间表
        try
        {
            (new OrdersGoods())->insertAll($array);
        }
        catch (Exception $e)
        {
            return false;
        }

        return true;
    }

    /**
     * 会员下单
     * @param $orders
     * @param $gid
     * @return bool
     */
    private function pay_vip($orders, $gid)
    {
        return OrdersLib::UpdateVipStatus($orders, $gid);
    }

    /**
     * 生成订单，并下单
     * @param $param ['order_type','trade_type','rid','cid','reid','gids','goods_info','price'，'start_time','out_trade_no','account','extend','pay_des','openid']
     * @return array|bool|Json
     * @throws Exception
     */
    private function SaveOrder($param)
    {
        $middle_res = true;
        $CouponModel = new UserCoupon();
        $orderModel = new OrdersCacheModel();
        Db::startTrans();
        try
        {
            //若是运势，则添加运势中间表数据
            if (in_array((int)$param['order_type'], [2, 3, 4], true))
            {
                $middle_res = $this->pay_fortune($param['rid'], $param['start_time'], $param['order_type']);
            }
            if ($middle_res == false)
            {
                throw new ApiException('下单失败,请重新操作');
            }
            //生成订单数据
            $insert = [
                'order_type' => $param['order_type'],
                'uid' => $this->user['id'],
                'gid' => $param['gids'][0],
                'order_id' => $param['out_trade_no'],
                'reid' => $param['reid'],
                'fid' => $middle_res,
                'trade_type' => $param['trade_type'],
                'total_amount' => $param['price'],
                'create_time' => $this->request->time(),
                'status' => 0,
                'account' => $param['account'],
                'extend' => $param['extend']
            ];
            // 生成订单到数据库
            try
            {
                //生成订单数据
                $oid = $orderModel->SaveData($insert);
                if ($oid === false)
                {
                    throw new ApiException('下单失败,请重新操作');
                }
            }
            catch (Exception $e)
            {
                Log::write('订单入库失败：' . $e->getMessage() . '【' . $e->getFile() . $e->getLine() . '】', 'error');
                throw new ApiException('操作失败,请重新操作');
            }
            //修改优惠券状态为已锁定
            if ($param['cid'])
            {
                $res = $CouponModel->use_return($this->user['id'], $param['cid'], ['status' => 4, 'oid' => $oid, 'update_time' => $this->request->time()]);
                if ($res === false)
                {
                    throw new ApiException($CouponModel->getError());
                }
            }

            //检测订单关闭入队
            PushQueue::CloseOrder($param['out_trade_no']);
            //若是地图，则添加地图中间表数据
            if ($param['order_type'])
            {
                $middle_res = $this->pay_map($param['rid'], $param['gids'], $oid);
            }
            if ($middle_res == false)
            {
                throw new ApiException('下单失败,请重新操作');
            }

            //更新订单详情缓存
            $orderModel->UpdateCache($param['out_trade_no'], 0);
            Db::commit();
        }
        catch (Exception $e)
        {
            Db::rollback();
            Log::write('入库失败信息：' . $e->getMessage() . '【' . $e->getFile() . $e->getLine() . '】', 'error');
            throw new ApiException('下单失败,请重新操作');
        }

        //支付订单
        $arr = OrdersLib::unifyPayOrder([
            'oid' => $oid,
            'trade_type' => $param['trade_type'],
            'total_amount' => $param['price'],
            'pay_des' => $param['pay_des'],
            'order_id' => $param['out_trade_no'],
            'openid' => $param['openid'],
            'callback_url' => '',
            'order_type' => $param['order_type']
        ], 1);
        $new_gid = [];
        foreach ($param['gids'] as $gid)
        {
            $new_gid[] = 'apple_pay_' . $gid;
        }
        $skuId = implode(',', $new_gid);

        if ($this->headers['app-type'] == 'ios')
        {
            $arr['data']['skuId'] = $skuId;
        }
        return $arr;
    }

    /**
     * 生成订单数据并入队
     * @param $param [cid,rid,start_time,order_type,gids,out_trade_no,reid,extend,goods_info]
     * @return array
     * @throws ApiException
     * @throws Exception
     */
    private function SaveFreeOrder($param)
    {
        $middle_res = true;
        $CouponModel = new UserCoupon();
        $now_time = $this->request->time();
        $gid = current($param['gids']);
        //订单状态
        switch (true)
        {
            case  in_array((int)$param['order_type'], [1, 3, 4], true) || ((int)$param['order_type'] === 5 && in_array((int)$gid, [18, 19], true))://需要计算的订单
                $status = 1;
                break;
            case in_array((int)$param['order_type'], [2, 6, 8], true) || ((int)$param['order_type'] === 5 && !in_array((int)$gid, [18, 19], true))://无需计算的订单
                $status = 4;
                break;
            default:
                $status = 1;
                break;
        }
        Db::startTrans();
        try
        {
            //若是运势，则添加运势中间表数据
            if (in_array((int)$param['order_type'], [2, 3, 4], true))
            {
                $middle_res = $this->pay_fortune($param['rid'], $param['start_time'], $param['order_type']);
            }
            if ($middle_res == false)
            {
                throw new ApiException('下单失败,请重新操作');
            }
            //生成订单数据
            $insert = [
                'order_type' => $param['order_type'],
                'uid' => $this->user['id'],
                'gid' => $gid,
                'order_id' => $param['out_trade_no'],
                'reid' => $param['reid'],
                'fid' => $middle_res,
                'trade_type' => $param['trade_type'],
                'total_amount' => 0,
                'create_time' => $now_time,
                'update_time' => $now_time,
                'pay_time' => $now_time,
                'status' => $status,
                'account' => 0,
                'extend' => $param['extend']
            ];
            // 生成订单到数据库
            $OrdersCacheModel = new OrdersCacheModel();
            try
            {
                //生成订单数据
                $oid = $OrdersCacheModel->SaveData($insert);
                if ($oid === false)
                {
                    throw new ApiException('下单失败,请重新操作');
                }
                //商品购买人数自增,教学视频根据课程进行缓存数据
                if ((int)$param['order_type'] === 6)
                {
                    $OrdersCacheModel->SaveTotalPrepaidOrder($param['order_type'], $gid);
                } else
                {
                    $OrdersCacheModel->SaveTotalPrepaidOrder($param['order_type'], 0);
                }
            }
            catch (Exception $e)
            {
                Log::write('订单入库失败：' . $e->getMessage() . '【' . $e->getFile() . $e->getLine() . '】', 'error');
            }

            //修改优惠券状态为已锁定
            if ($param['cid'])
            {
                $res = $CouponModel->use_return($this->user['id'], $param['cid'], ['status' => 1, 'oid' => $oid, 'update_time' => $now_time]);
                if ($res === false)
                {
                    throw new ApiException($CouponModel->getError());
                }
            }

            //生成第三方数据和入队
            switch (true)
            {
                case (int)$param['order_type'] === 5://若是地图，则添加地图中间表数据
                    $middle_res = $this->pay_map($param['rid'], $param['gids'], $oid);
                    break;
                case (int)$param['order_type'] === 8://若是vip，更新vip有效期和生效状态
                    $middle_res = $this->pay_vip($insert, $gid);
                    break;
            }
            //更新星力值
            if ((int)$param['order_type'] !== 8)
            {   // VIP订单除外 更新星力值，  VIP星力值已经更新过了，禁止重复更新
                OrdersLib::UpdateVipBoon($insert, $gid, true);
            }
            if ($middle_res == false)
            {
                throw new ApiException('下单失败,请重新操作');
            }

            //更新订单详情缓存
            $OrdersCacheModel->UpdateCache($param['out_trade_no'], $status);
            Db::commit();
        }
        catch (Exception $e)
        {
            Db::rollback();
            throw new ApiException('下单失败,请重新操作');
        }
        //生成第三方数据和入队
        switch (true)
        {
            case (int)$param['order_type'] === 1://校准生辰入队
                $this->RecQueue($param['reid'], $oid, $param['out_trade_no']);
                break;
            case in_array((int)$param['order_type'], [3, 4], true)://运势入队
                $this->FortuneQueue($this->user['id'], $oid);
                break;
            case (int)$param['order_type'] === 5://地图入队
                (new PushQueue())->Map($param['out_trade_no']);
                break;
        }
        return $param['out_trade_no'];
    }

    /**
     * 校准生辰入队
     * @param $reid
     * @param $oid
     * @param $out_trade_no
     * @throws Exception
     */
    private function RecQueue($reid, $oid, $out_trade_no)
    {
        (new PushQueue())->Rectification($this->user, $reid, $oid, $out_trade_no);
    }

    /**
     * 运势入队
     * @param $uid
     * @param $oid
     * @return bool|mixed
     * @throws Exception
     */
    private function FortuneQueue($uid, $oid)
    {
        return (new PushQueue)->Fortune(['uid' => $uid, 'oid' => $oid]);
    }
}
